import { Color, Frustum,  Matrix4, Mesh,  PerspectiveCamera, Plane, Vector3, Vector4 } from "three";
import { App, Point } from "../../Engine";
import Helper from "../../utils/Helper";
import { TransformControls } from "three/examples/jsm/controls/TransformControls";
import FrustumLineFrame from "../models/FrustumLineFrame";
import DepthTargetHelper from "../../utils/DepthTargetHelper";
import Events from "../../application/constants/Events";

/**
 * 可视域分析
 */
export default class ViewFieldAnalysis {
    private app;
    private virturalCamera: PerspectiveCamera;
    private planeArray: Plane[];
    private lineObject: FrustumLineFrame;
    private isOpenAnalysis: boolean = false;
    private transformControls: TransformControls;
    private transformControls2: TransformControls;
    private viewFieldColor: string;
    private viewFieldColorVector: Vector3;
    private depthTargetHelper: DepthTargetHelper;
    private isCoverShadow: boolean = false;
    private shadowColorVector: Vector3;
    private refreshEvent;

    /**
     * 可视域分析
     * @param viewFieldColor 可视域内的颜色
     * @example 
        let viewFieldColor = '#7FFF00'; //可视域内的颜色
        let viewFieldAnalysis = new GE.ViewFieldAnalysis(viewFieldColor);
        let aspect = 1.2722371967654986;
        let cameraParam = {
            cameraPosition: new GE.Point(13377542.119303564, 3540032.0606621173, 100, '3857'),
            targetPosition: new GE.Point(13377184.375437068, 3545339.2581293588, 0, '3857'),
            fov: 40,
            aspect: aspect,
            near: 200,
            far: 1000,
        }
        viewFieldAnalysis.openAnalysis(cameraParam); //打开可视域分析
        //viewFieldAnalysis.closeAnalysis(); //关闭可视域分析
     */
    public constructor(viewFieldColor?:string) {
        this.app = App.getInstance();
        this.viewFieldColor = (viewFieldColor ? viewFieldColor : '#00FA9A');

        let colorVector = new Color(this.viewFieldColor);
        this.viewFieldColorVector = new Vector3(colorVector.r, colorVector.g, colorVector.b);
    }

    private updateCamera(data: {cameraPosition: Vector3, matrix: Matrix4}){
            this.depthTargetHelper.preRenderTarget(this.virturalCamera);
            
            this.getFrustumPlanes();
            this.updateMaterials();
    }

    private getFrustumPlanes(){
        this.virturalCamera.updateMatrix();
        this.virturalCamera.updateWorldMatrix(true, true);
        this.virturalCamera.updateMatrixWorld(true);
        this.virturalCamera.updateProjectionMatrix();

        let virturalFrustum = new Frustum();
        virturalFrustum.setFromProjectionMatrix(this.virturalCamera.projectionMatrix.clone().multiply(this.virturalCamera.matrixWorldInverse) );
        this.planeArray = virturalFrustum.planes;
    }
    
    private updateMaterials(){
         let frustumPlanes: Array<Vector4> = new Array<Vector4>();
         this.planeArray.forEach(element => {
             let normal = element.normal;
             let distance = element.constant;

             let plane = new Vector4(normal.x, normal.y, normal.z, distance);
             frustumPlanes.push(plane);
         });

        let depthTexture = this.depthTargetHelper.renderTarget.depthTexture;
        let viewMatrixViewField = this.virturalCamera.matrixWorld.clone();
        let projectMatrixViewField = this.virturalCamera.projectionMatrix.clone();
        let viewFieldData = {isOpenViewField: true, viewFieldColor: this.viewFieldColorVector, viewFieldDepthTexture: depthTexture,
             viewMatrix_ViewField: viewMatrixViewField, projectMatrix_ViewField: projectMatrixViewField, 
             isCoverShadow_ViewField: this.isCoverShadow, shadowColor_ViewField: this.shadowColorVector};
        this.updateSceneMaterial(viewFieldData);
    }

    /**
     * 设置阴影遮挡
     * @param coverData 设置阴影遮挡的数据
     * @param coverData.isCoverShadow true：遮挡阴影，false：不遮挡阴影
     */
    public setCoverShadow(coverData: {isCoverShadow: boolean, shadowColor: string}){
        this.isCoverShadow = coverData.isCoverShadow;

        let colorVector = new Color(coverData.shadowColor);
        this.shadowColorVector = new Vector3(colorVector.r, colorVector.g, colorVector.b);

        this.updateMaterials();
    }

    private updateSceneMaterial(viewFieldData){
        Helper.traverseObject(this.app.three.scene, function (obj) {
            try {
                if (obj.type == 'Mesh') {
                    if(obj.material.length > 1){
                        obj.material.forEach(element => {
                            if(element.material.setVewField){
                                element.material.setVewField(viewFieldData);
                            }
                        });
                    }else{
                        if(obj.material.setVewField){
                            obj.material.setVewField(viewFieldData);
                        }
                    }
                   
                }
            } catch (error) {
                console.log(error);
            }

            return true;
        });
    }

    /**
     * 打开可视域分析
     * @param cameraParam 可视域分析需要用到的相机参数
     * @param cameraParam.cameraPosition 相机的位置
     * @param cameraParam.targetPosition 相机看向的位置
     * @param cameraParam.fov 相机的可视角度
     * @param cameraParam.aspect 相机投影的长宽比例
     * @param cameraParam.near 相机的近平面
     * @param cameraParam.far 相机的远平面
     */
    public openAnalysis(cameraParam: { cameraPosition: Point, targetPosition: Point, fov: number, aspect: number, near: number, far: number}){
        if(this.isOpenAnalysis){
            return;
        }
        this.isOpenAnalysis = true;

        cameraParam.cameraPosition.toEPSGWeb();
        this.virturalCamera = new PerspectiveCamera(cameraParam.fov, cameraParam.aspect, cameraParam.near, cameraParam.far);
        this.virturalCamera.position.copy(cameraParam.cameraPosition);

        cameraParam.targetPosition.toEPSGWeb();

        this.virturalCamera.up.set(0, 0, 1);
        this.virturalCamera.lookAt(cameraParam.targetPosition);
        this.app.add(this.virturalCamera);

        this.lineObject = new FrustumLineFrame(this.virturalCamera, this.viewFieldColor);
        // this.lineObject.position.copy(cameraParam.cameraPosition);
        this.app.add(this.lineObject);

        this.depthTargetHelper = new DepthTargetHelper();
        this.depthTargetHelper.initRenderTarget();
        this.depthTargetHelper.preRenderTarget(this.virturalCamera);

        this.getFrustumPlanes();
        this.updateMaterials();

        this.refreshEvent = Helper.debounce2(this.updateMaterials.bind(this), 100, false);
        this.app.on(Events.AddTile, this.refreshEvent);
    }

    /**
     * 关闭可视域分析
     */
    public closeAnalysis(){
        this.hideControl();

        this.depthTargetHelper.renderTarget.depthTexture.dispose();
        this.depthTargetHelper.renderTarget.dispose();
        this.depthTargetHelper = null;

        let viewFieldData = {isOpenViewField: false, frustumPlanes: null, frustumPlaneCount: 6, viewFieldColor: this.viewFieldColorVector, viewFieldDepthTexture: null, viewMatrix_ViewField: null, projectMatrix_ViewField: null, isCoverShadow_ViewField: false}
        this.updateSceneMaterial(viewFieldData);

        this.app.remove(this.lineObject);
        this.isOpenAnalysis = false;
        
        this.app.off(Events.AddTile, this.refreshEvent);
    }
    
     /**
     * 打开可视域分析控制器，并且设置控制器的模式
     * @param model 控制器的模式：'translate'表示移动模式; 'rotate'表示旋转模式
     */
    public setControlModel(model: 'translate' | 'rotate'){
        if (!this.transformControls) {
            this.transformControls = new TransformControls(this.app.three.camera, this.app.three.renderer.domElement);
            this.setTransformControl(this.transformControls);
            this.app.add(this.transformControls.getHelper());

            this.transformControls2 = new TransformControls(this.app.three.camera, this.app.three.renderer.domElement);
            // this.setTransformControl(this.transformControls2);
            this.app.add(this.transformControls2.getHelper());
        }
        this.transformControls.attach(this.virturalCamera);
        this.transformControls.setMode(model);
        
        this.transformControls2.attach(this.lineObject);
        this.transformControls2.setMode(model);
    }

    /**
     * 关闭控制器
     */
    public hideControl() {
        if (!this.transformControls) {
            return;
        }
        
        this.app.remove(this.transformControls.getHelper());
        this.transformControls.detach();
        this.transformControls.dispose();
        this.transformControls = null;

        this.app.remove(this.transformControls2.getHelper());
        this.transformControls2.detach();
        this.transformControls2.dispose();
        this.transformControls2 = null;
    }
    
    private setTransformControl(transformControls) {
        transformControls.enabled = true;
        Helper.traverseObject(transformControls, function (element) {
            if (element instanceof Mesh || element.type == 'Mesh') {
                element.material.clippingPlanes = null;
            }
        });
        let self = this;
        transformControls.addEventListener('rotationAngle-changed', function (event) {
            let modelMatrix: Matrix4 = event.target.object.matrixWorld;
            self.updateCamera({cameraPosition: null, matrix: modelMatrix})
        });
        transformControls.addEventListener('dragging-changed', function (event) {
            self.app.camera.orbit.enabled = !event.value;
        });
        transformControls.addEventListener('change', function (event) {
            if(!event.target.object){
                return;
            }
            let targetPosition = event.target.object.position;
            self.updateCamera({cameraPosition: targetPosition, matrix: null})
        });
    }

}